#include <stdlib.h>
#include "estatisticas.h"
#include "modoDebug.h"
#include "maquinaVirtual.h"
#include "reposicaoPagina.h"
#include "io.h"


void reposicaoPaginaPorLRU(Estatisticas *estatistica)
{
	unsigned qtPags = (estatistica->tamanhoMemoria / estatistica->tamanhoPagina), i, pagLoad = 0, menorTempo = 0, addr, numPag, tempo = 0;
	char rw;
	int* tabPag = malloc(MAX_TAB_PAGINA * sizeof(int));
	FILE *flArquivo;
	Pagina paginas[qtPags];
	inicializaPagina(paginas, qtPags);
	Config(estatistica->entrada, "LRU", estatistica->tamanhoMemoria, estatistica->tamanhoPagina, qtPags, "LRU.log");
	flArquivo = abreArquivoEntrada(estatistica->entrada);

	while (!feof(flArquivo))
	{
		fscanf(flArquivo, "%x %c", &addr, &rw);
		numPag = numeroPagina(addr, estatistica->tamanhoPagina); //número da página acessada
		i = tabPag[numPag]; //indice da pagina na memoria
		if (numPag == paginas[i].numPagina)
		{
			if(rw == 'R')
				paginas[i].dirtyBit = (rw == 'W');
			paginas[i].tempo = tempo;
			estatistica->paginasLidas++;
			EncontrouPag(numPag,rw, i,"LRU.log");
		}
		else if (pagLoad < qtPags)
		{
			//tem quadros livres na memória
			AlocouLivre(numPag, rw, pagLoad, "LRU.log");
			paginas[pagLoad].numPagina = numPag;
			paginas[pagLoad].tempo = tempo;
			paginas[pagLoad].dirtyBit = (rw == 'W');
			tabPag[numPag] = pagLoad;
			pagLoad++;
			estatistica->pageFault++;
			estatistica->paginasLidas++;
		}
		else
		{
			//pagina nao esta carregada e nao tem espaço livre na memoria, logo tera q ser substituida
			for (i = 0; i < qtPags; i++)
			{
				if (paginas[i].tempo < paginas[menorTempo].tempo)
				{
					//encontra o indice da pagina mais antiga para trocar
					menorTempo = i;
				}
			}
			if (paginas[menorTempo].dirtyBit)
			{
				//pagina escrita de volta ao disco
				estatistica->paginasEscritas++;
			}
			Substitui(numPag,rw,paginas[menorTempo].numPagina,paginas[menorTempo].dirtyBit,menorTempo,"LRU.log");
			tabPag[numPag] = menorTempo;			//nova página é colocada no lugar da que saiu
			paginas[menorTempo].numPagina = numPag;
			paginas[menorTempo].tempo = tempo;
			paginas[menorTempo].dirtyBit = (rw == 'W');
			estatistica->pageFault++;
			estatistica->paginasLidas++;
		}
		tempo++;
	}
	free(tabPag);
	fechaArquivo(flArquivo);
	imprimeEstatisticas(estatistica);
}

void reposicaoPaginaPorFIFO(Estatisticas *estatistica)
{
	unsigned qtPags = (estatistica->tamanhoMemoria/ estatistica->tamanhoPagina), i, pagLoad = 0, primFila = 0, addr, numPag;
	char rw;
	int* tabPag = malloc(MAX_TAB_PAGINA * sizeof(int));
	FILE *flArquivo;
	Pagina paginas[qtPags];
	inicializaPagina(paginas, qtPags);
	Config(estatistica->entrada, "FIFO", estatistica->tamanhoMemoria, estatistica->tamanhoPagina, qtPags, "FIFO.log");
	flArquivo = abreArquivoEntrada(estatistica->entrada);
	while (!feof(flArquivo))
	{
		fscanf(flArquivo, "%x %c", &addr, &rw);
		numPag = numeroPagina(addr, estatistica->tamanhoPagina); //número da página acessada
		i = tabPag[numPag]; //indice da pagina na memoria
		if (numPag == paginas[i].numPagina)
		{
			if(rw == 'R')
				paginas[i].dirtyBit = (rw == 'W');
			estatistica->paginasLidas++;
			EncontrouPag(numPag,rw, i,"FIFO.log");
		}
		else if (pagLoad < qtPags)
		{
			//tem quadros livres na memória
			AlocouLivre(numPag, rw, pagLoad, "FIFO.log");
			paginas[pagLoad].numPagina = numPag;
			paginas[pagLoad].dirtyBit = (rw == 'W');
			tabPag[numPag] = pagLoad;
			pagLoad++;
			estatistica->pageFault++;
			estatistica->paginasLidas++;
		}
		else
		{
			//pagina nao esta carregada e nao tem espaço livre na memoria, logo tera q ser substituida
			if (paginas[primFila].dirtyBit)
			{
				//pagina escrita de volta ao disco
				estatistica->paginasEscritas++;
			}
			Substitui(numPag,rw,paginas[primFila].numPagina,paginas[primFila].dirtyBit,primFila,"FIFO.log");
			tabPag[numPag] = primFila;			//nova página é colocada no lugar da que saiu
			paginas[primFila].numPagina = numPag;
			paginas[primFila].dirtyBit = (rw == 'W');
			estatistica->pageFault++;
			estatistica->paginasLidas++;
			if(primFila < qtPags-1)
			{
				primFila++;
			}
			else
			{
				primFila = 0;
			}
		}
	}
	free(tabPag);
	fechaArquivo(flArquivo);
	imprimeEstatisticas(estatistica);
}

void reposicaoPaginaRandom(Estatisticas *estatistica)
{
	unsigned qtPags = (estatistica->tamanhoMemoria / estatistica->tamanhoPagina), i, pagLoad = 0, aleatorio = 0, addr, numPag;
	char rw;
	int* tabPag = malloc(MAX_TAB_PAGINA * sizeof(int));
	FILE *flArquivo;
	Pagina paginas[qtPags];
	inicializaPagina(paginas, qtPags);
	Config(estatistica->entrada, "FIFO", estatistica->tamanhoMemoria, estatistica->tamanhoPagina, qtPags, "RANDOM.log");
	flArquivo = abreArquivoEntrada(estatistica->entrada);
	while (!feof(flArquivo))
	{
		fscanf(flArquivo, "%x %c", &addr, &rw);
		numPag = numeroPagina(addr, estatistica->tamanhoPagina); //número da página acessada
		i = tabPag[numPag]; //indice da pagina na memoria
		if (numPag == paginas[i].numPagina)
		{
			//pagina ja estava carregada, se ela ja estava alterada
			//entao mantem como alterada, senao testa se foi alterada agora
			if(rw == 'R')
				paginas[i].dirtyBit = (rw == 'W');
			estatistica->paginasLidas++;
			EncontrouPag(numPag,rw, i, "RANDOM.log");
		}
		else if (pagLoad < qtPags)
		{
			//tem quadros livres na memória
			AlocouLivre(numPag, rw, pagLoad, "RANDOM.log");
			paginas[pagLoad].numPagina = numPag;
			paginas[pagLoad].dirtyBit = (rw == 'W');
			tabPag[numPag] = pagLoad;
			pagLoad++;
			estatistica->pageFault++;
			estatistica->paginasLidas++;
		}
		else
		{
			//pagina nao esta carregada e nao tem espaço livre na memoria, logo tera q ser substituida
			srand(time(NULL));
			aleatorio = rand() % qtPags;
			Substitui(numPag,rw,paginas[aleatorio].numPagina,paginas[aleatorio].dirtyBit,aleatorio, "RANDOM.log");
			if (paginas[aleatorio].dirtyBit)
			{
				//pagina escrita de volta ao disco
				estatistica->paginasEscritas++;
			}

			tabPag[numPag] = aleatorio;			//nova página é colocada no lugar da que saiu
			paginas[aleatorio].numPagina = numPag;
			paginas[aleatorio].dirtyBit = (rw == 'W');
			estatistica->pageFault++;
			estatistica->paginasLidas++;
		}
	}
	free(tabPag);
	fechaArquivo(flArquivo);
	imprimeEstatisticas(estatistica);
}
